package ms.unicorn.reasoning;

import java.util.HashSet;
import java.util.Set;

public class DAT extends HashSet<AnnotatedAlternative> {

	private static final long serialVersionUID = 1L;

	public DAT() {
		
	}
	
	public DAT(int cap) {
		super(cap);
	}
	
	public DAT(DAT dat) {
		super(dat);
	}
	
	public DAT applyProbability(float p, String possibility) {
		DAT dat = new DAT(this.size());
		for (AnnotatedAlternative alt: this)
			dat.add(new AnnotatedAlternative(alt, alt.mb * p, 1 - (1 - alt.rr) * p, possibility));
		return dat;
	}
	
	@Override
 	public String toString() {
		String s = "[";
		for(AnnotatedAlternative alt: this)
			s += alt.toString() + " ";
		s += "]";
		return s;
	}
	
	public static DAT concat(DAT a, DAT b) {		
		DAT result = new DAT( (a!= null ? a.size() : 0)+ (b!=null ? b.size(): 0));
		if (a != null) result.addAll(a);
		if (b != null) result.addAll(b);
			
		result.filter();
		
		return result;
	}
	
	public static DAT join(DAT a, DAT b) {
		if (a == null) return new DAT(b);
		if (b == null) return new DAT(a);
		
		DAT result = new DAT(a.size() * b.size());

		for(AnnotatedAlternative ae: a)
			for (AnnotatedAlternative be: b)
				result.add(AnnotatedAlternative.join(ae,  be));
		result.filter();
		return result;
	}
	
	private void filter() {
		AnnotatedAlternative alts[] = this.toArray(new AnnotatedAlternative[size()]);
		for (int i = 0; i < alts.length - 1; i++) 
			if (contains(alts[i])) 
				for (int j = i+1; j < alts.length; j++) 
					if (contains(alts[j])) {
						if (alts[i].isGreaterEqual(alts[j], true )) {
							remove(alts[i]);
							break;
						} else if (alts[j].isGreaterEqual(alts[i], true))
							remove(alts[j]);
					}
	}

	public boolean addAlternative(FDNode node, int mb, int rr) {
		AnnotatedAlternative alt = new AnnotatedAlternative(node, mb, rr);
		return add(alt);
	}
	
	public DAT consolidate() {
		DAT alternative = new DAT();
		for(AnnotatedAlternative alt: this) {
			FinalAnnotatedAlternative a = new FinalAnnotatedAlternative();
			a.addAll(alt);
			if (!alternative.contains(a))
				alternative.add(calculateMetric(a));
		}
		return alternative;
	}
	
	public FinalAnnotatedAlternative calculateMetric(FinalAnnotatedAlternative alt) {
		Set<String> sda;
		sda = new HashSet<String>();
		float mb = 0, db = 1, md = 0;
		for (AnnotatedAlternative a: this) {
			if (!sda.contains(a.getEvolutionPath())) {
				if (alt.isGreaterEqual(a, false)) {
					mb = Math.max(mb, a.getMaxBelief());
					db = db + a.getDeferalBelief() - 1;
					sda.add(a.evolutionPath);
				}
			}
		}
		for (AnnotatedAlternative a: this) 
			if (!sda.contains(a.getEvolutionPath())) {
				md = Math.max(md, a.getMaxBelief());
			}
		alt.setMaxDisbelief(md);
		alt.setMaxBelief(mb);
		alt.setRR(db);
		return alt;
	}
}
